package model.channel;

import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import model.invocatedMethods.GetValueCallable;
import model.observer.SensorObserver;
import model.subject.Sensor;
import model.algorithmes.SpreadingAlgorithme;

import commands.Command;
import constants.Constants;

import model.value.VersionnedValue;
import factory.ExecutorFactory;
import model.invocatedMethods.RunnableUpdateImpl;

/**
 * Implémentation de l'interface Channel.
 */
public class ChannelImpl implements Channel {

	private Sensor sensor;
	private SensorObserver sensorObserver;

	private long latency;
	private boolean isLatencyRandom;
	
	private Future<VersionnedValue> future;	// Future dans lequel sera stocké la valeur du capteur
	
	@Override
	public void setLatency(long latency) {
		this.latency = latency;
		
		if(latency == 0) {
			isLatencyRandom = true;
		}
	}

	@Override
	public void update(Sensor subject) {
		if(isLatencyRandom) {
			Double randomLatency = Math.random() * (Constants.CHANNEL_MAX_LATENCY - Constants.CHANNEL_MIN_LATENCY) + Constants.CHANNEL_MIN_LATENCY;
			latency = randomLatency.intValue();
		}
		
		ExecutorFactory.getInstance().execute(new RunnableUpdateImpl(sensorObserver, this, latency));
	}

	@Override
	public void setSensor(Sensor sensor) {
		this.sensor = sensor;
	}

	@Override
	public void setSensorObserver(SensorObserver sensorObserver) {
		this.sensorObserver = sensorObserver;
	}	

	@Override
	public VersionnedValue getValue() {
		if(isLatencyRandom) {
			Double randomLatency = Math.random() * (Constants.CHANNEL_MAX_LATENCY - Constants.CHANNEL_MIN_LATENCY) + Constants.CHANNEL_MIN_LATENCY;
			latency = randomLatency.intValue();
		}
		
		Callable<VersionnedValue> callable = new GetValueCallable(sensor, latency);
		future = ExecutorFactory.getInstance().submit(callable);
		
		try {
			return future.get();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	@Override
	public void attach(SensorObserver observer) {
	}

	@Override
	public void detach(SensorObserver observer) {		
	}
	
	@Override
	public void setRealValue(int value) {
	}
	
	@Override
	public VersionnedValue getRealValue() {
		return null;
	}


	@Override
	public void setSpreadingAlgorithme(SpreadingAlgorithme spreadingAlgorithme) {
	}

	@Override
	public void setValue(int value) {
	}

	@Override
	public void setNotifyChangesToDisplayerPanelCommand(Command notifyChangesToDisplayerPanelCommand) {
	}

	@Override
	public void setNotifyChangesToApplicationPanelCommand(Command notifyChangesToApplicationPanelCommand) {	
	}

	@Override
	public Collection<SensorObserver> getObservers() {
		return null;
	}

}
